<?php

namespace addon\lian\model\core\member;

use addon\lian\model\Config;
use addon\lian\model\core\order\CoreLianRewardService;
use addon\lian\model\sqlmodel\LianMemberModel;
use addon\lian\model\sqlmodel\LianPubLineModel;
use addon\lian\model\sqlmodel\MemberModel;
use addon\lian\model\sqlmodel\OrderGoodsModel;
use app\dict\order\OrderGoodsDict;
use think\facade\Db;
use think\facade\Log;

class CorePublineService
{
    /**
     * 添加会员到公排
     * @param int $site_id 站点ID
     * @param int $member_id 会员ID
     * @param int $pid 直推上级ID
     * @return bool
     */
    public function addMemberPubline($site_id, $member_id, $order_data)
    {
        try {
            Log::info('addMemberPubline开始');
            // 获取配置信息
            $config = (new Config())->getLianBasicsConfig($site_id);
            $config = $config['data']['value'];
            
            // 检查是否开启公排
            if ($config['is_publine'] == 0) {
                Log::write('========ly_lian========addMemberPubline===========公排未开启，直接返回。');
                return false;
            }

            $goods_ids = (new CoreLianRewardService())->getLianGoodsIds($site_id);
            $order_goods = (new OrderGoodsModel())->alias('og')
                ->where('og.site_id', $site_id)
                ->where('og.member_id', $member_id)
                ->where('og.order_id', $order_data['order_id'])
                ->whereIn('og.goods_id', $goods_ids)
                ->join('order o', 'og.order_id = o.order_id', 'INNER')
                ->whereIn('o.order_status',  [OrderGoodsDict::wait_delivery, OrderGoodsDict::delivery, OrderGoodsDict::delivery_finish])
                ->findOrEmpty();
            Log::write('========ly_lian========handleReward===========order_goods:'.json_encode($order_goods));
            // $order_member = (new MemberModel())->where('site_id', $site_id)->where('member_id', $order_data['member_id'])->findOrEmpty();
    
            if(!$order_goods) {
                Log::write('========ly_lian========addMemberPubline===========订单中没有链动商品，直接返回。');
                return false; // 订单中没有联营商品，直接返回。
            }
            
            // 获取链动会员信息
            $member = (new LianMemberModel())->where('site_id', $site_id)->where('member_id', $member_id)->findOrEmpty();
            // if ($member->isEmpty()) {
            //     return false;
            // }
            $pid = Db::name('fenxiao')->where('site_id', $site_id)->where('member_id', $member_id)->value('parent');
            
            // 判断公排类型
            $publine_type = $config['publine_type'] ?? 1; // 默认为小公排
            $publine_mode = $config['publine_mode'] ?? 3; // 默认为三三公排
            
            // 设置每个节点的最大子节点数量
            $max_children = 2;
            if ($publine_mode == 2) {
                $max_children = 3;
            } elseif ($publine_mode == 3) {
                $max_children = 5;
            }
            
            // 获取可用位置信息
            $position_info = $this->findAvailablePosition($site_id, $member_id, $pid, $publine_type, $max_children);
            
            // 如果找不到合适的位置，则放在根节点
            if (empty($position_info)) {
                $position_info = [
                    'up_pid' => 0,
                    'position' => 1,
                    'path' => '', // 根节点的path为空字符串
                    'level' => 1,
                    'is_fu' => 0 // 根节点第一个位置不是财富点位
                ];
            }

            Log::info('position_info:' . json_encode($position_info));
            
            // 开始事务
            Db::startTrans();
            try {
                // 添加到公排表
                $publine_data = [
                    'site_id' => $site_id,
                    'member_id' => $member_id,
                    'pid' => $pid,
                    'up_pid' => $position_info['up_pid'],
                    'level' => $position_info['level'],
                    'path' => $position_info['path'],
                    'position' => $position_info['position'],
                    'team_count' => 0,
                    'direct_count' => 0,
                    'left_count' => $max_children, // 新会员下方仍有max_children个位置
                    'is_full' => 0,
                    'publine_type' => 0, // 公排类型：0公排
                    'is_fu' => $position_info['is_fu'],
                    'status' => 0,
                    'create_time' => time(),
                    'update_time' => time()
                ];
                Log::info('publine_data:' . json_encode($publine_data));
                (new LianPubLineModel())->insert($publine_data);
                
                // 更新上级节点的left_count、direct_count和is_full状态
                if ($position_info['up_pid'] > 0) {
                    // 获取非财富点位的可用位置数
                    $non_fu_positions = $this->countNonFuAvailablePositions($site_id, $position_info['up_pid'], $max_children);
                    
                    $update_data = [
                        'left_count' => max(0, ['dec', 1]), // 减少一个可用位置
                        // 'team_count' => ['inc', 1], // 增加一个团队成员
                        'update_time' => time()
                    ];
                    
                    // 如果是直推，增加直推计数
                    if ($position_info['up_pid'] == $pid) {
                        $update_data['direct_count'] = ['inc', 1];
                    }
                    
                    // 如果非财富点位已满，则标记为已满
                    // if ($non_fu_positions <= 1) { // 小于等于1是因为我们还没更新数据库，当前操作会减少一个位置
                    if ($non_fu_positions == $max_children) { // 小于等于1是因为我们还没更新数据库，当前操作会减少一个位置
                        $update_data['is_full'] = 1;
                    }
                    
                    (new LianPubLineModel())
                        ->where('member_id', $position_info['up_pid'])
                        ->update($update_data);
                    
                    // 更新path路径上的所有父节点的team_count
                    $this->updateParentTeamCounts($site_id, $position_info['path']);
                }

                // 绑定会员关系
                // (new CoreLianMemberService())->bindChildMember($site_id, $member_id, $order_data);
                
                Db::commit();
                return true;
            } catch (\Exception $e) {
                Db::rollback();
                Log::error('链动公排添加会员失败：' . $e->getMessage() . 'line:' . $e->getLine() . 'file:' . $e->getFile());
                return false;
            }
        } catch (\Exception $e) {
            Log::error('链动公排添加会员异常：' . $e->getMessage() . 'line:' . $e->getLine() . 'file:' . $e->getFile());
            return false;
        }
    }
    
    /**
     * 查找可用的位置
     * @param int $site_id 站点ID
     * @param int $member_id 会员ID
     * @param int $pid 直推上级ID
     * @param int $publine_type 公排类型
     * @param int $max_children 最大子节点数
     * @return array|null 位置信息
     */
    protected function findAvailablePosition($site_id, $member_id, $pid, $publine_type, $max_children)
    {
        Log::info('findAvailablePosition开始' . 'pid:' . $pid . 'member_id:' . $member_id . 'publine_type:' . $publine_type . 'max_children:' . $max_children);
        // 1. 优先尝试在直推上级下放置
        if ($pid > 0) {
            $position = $this->findPositionUnderDirectParent($site_id, $pid, $max_children);
            if ($position) {
                Log::info('findPositionUnderDirectParent结束' . 'position:' . json_encode($position));
                return $position;
            }
        }
        
        // 2. 如果直推上级下无位置，需要滑落
        if ($pid > 0) {
            $position = $this->findSlidePosition($site_id, $pid, $max_children);
            if ($position) {
                Log::info('findSlidePosition结束' . 'position:' . json_encode($position));
                return $position;
            }
        }
        
        // 3. 如果没有直推上级，放在网络中的任意可用位置
        $position = $this->findAvailablePositionInNetwork($site_id, $max_children);
        if ($position) {
            Log::info('findAvailablePositionInNetwork结束' . 'position:' . json_encode($position));
            return $position;
        }
        return null;
    }
    
    /**
     * 在直推上级下查找位置
     * @param int $site_id 站点ID
     * @param int $pid 直推上级ID
     * @param int $max_children 最大子节点数
     * @return array|null 位置信息
     */
    protected function findPositionUnderDirectParent($site_id, $pid, $max_children)
    {
        Log::info('findPositionUnderDirectParent开始' . 'pid:' . $pid . 'max_children:' . $max_children);
        $parent_publine = (new LianPubLineModel())
            ->where('site_id', $site_id)
            ->where('member_id', $pid)
            ->findOrEmpty();
            
        if ($parent_publine->isEmpty()) {
            return null;
        }
        
        // 获取直推上级下的直推会员数量
        $direct_count = (new LianPubLineModel())
            ->where('site_id', $site_id)
            // ->where('up_pid', $pid)
            ->where('pid', $pid) // 只统计直推的
            ->count();
            
        // 获取已占用的位置
        $occupied_positions = (new LianPubLineModel())
            ->where('site_id', $site_id)
            // ->where('up_pid', $pid)
            ->where('pid', $pid)
            ->column('position');
        
        // 财富点位是最后一个位置
        $fu_position = $max_children;
        
        // 判断是否应该放在财富点位
        if ($direct_count == $max_children - 1 && !in_array($fu_position, $occupied_positions)) {
            // 这是第N个直推（财富点位），且财富点位未被占用
            $new_path = $this->buildPath($parent_publine['path'], $pid);
            
            Log::info('findPositionUnderDirectParent结束' . 'new_path:' . $new_path);
            return [
                'up_pid' => $pid,
                'position' => $fu_position,
                'path' => $new_path,
                'level' => $parent_publine['level'] + 1,
                'is_fu' => 1 // 标记为财富点位
            ];
        }
        
        // 查找普通位置（1到max_children-1）
        if ($direct_count < $max_children - 1) {
            Log::info('findPositionUnderDirectParent结束' . 'direct_count:' . $direct_count . 'max_children:' . $max_children);
            for ($i = 1; $i < $max_children; $i++) {
                if (!in_array($i, $occupied_positions)) {
                    $new_path = $this->buildPath($parent_publine['path'], $pid);
                    Log::info('findPositionUnderDirectParent结束' . 'new_path:' . $new_path);
                    return [
                        'up_pid' => $pid,
                        'position' => $i,
                        'path' => $new_path,
                        'level' => $parent_publine['level'] + 1,
                        'is_fu' => 0 // 普通位置
                    ];
                }
            }
        }
        
        return null; // 直推上级下已满
    }
    
    /**
     * 查找滑落位置（只能滑落到直推上级财富点位下方的普通位置）
     * @param int $site_id 站点ID
     * @param int $pid 直推上级ID
     * @param int $max_children 最大子节点数
     * @return array|null 位置信息
     */
    protected function findSlidePosition($site_id, $pid, $max_children)
    {
        Log::info('findSlidePosition开始，直推上级：' . $pid);
        
        // 首先找到直推上级的财富点位成员（只能是直推的财富点位）
        $fu_member = (new LianPubLineModel())
            ->where('site_id', $site_id)
            ->where('pid', $pid)  // 必须是直推的
            ->where('is_fu', 1)   // 财富点位
            ->findOrEmpty();
            
        if ($fu_member->isEmpty()) {
            Log::info('直推上级无财富点位成员：' . $pid);
            return null;
        }
        
        Log::info('找到直推上级的财富点位成员：' . $fu_member['member_id']);
        
        // 在财富点位成员的下级分支中递归查找可用位置
        return $this->findPositionInWealthBranch($site_id, $fu_member['member_id'], $max_children);
    }
    
    /**
     * 在财富点位分支中递归查找可用位置
     * @param int $site_id 站点ID
     * @param int $wealth_member_id 财富点位成员ID
     * @param int $max_children 最大子节点数
     * @return array|null 位置信息
     */
    protected function findPositionInWealthBranch($site_id, $wealth_member_id, $max_children)
    {
        Log::info('在财富点位分支中查找位置：' . $wealth_member_id);
        
        // 先尝试在当前财富点位成员下方找普通位置
        $position = $this->findNonFuPositionUnderParent($site_id, $wealth_member_id, $max_children);
        if ($position) {
            Log::info('在财富点位直接下方找到位置：' . json_encode($position));
            return $position;
        }
        
        // 如果直接下方没位置，则在其所有子节点的分支中递归查找
        $children = (new LianPubLineModel())
            ->where('site_id', $site_id)
            ->where('up_pid', $wealth_member_id)
            ->order('position ASC') // 按位置顺序，优先左侧
            ->select()
            ->toArray();
            
        foreach ($children as $child) {
            // 递归在每个子分支中查找
            $position = $this->findPositionInWealthBranch($site_id, $child['member_id'], $max_children);
            if ($position) {
                Log::info('在财富点位子分支中找到位置：' . json_encode($position));
                return $position;
            }
        }
        
        Log::info('财富点位分支中无可用位置：' . $wealth_member_id);
        return null;
    }
    
    /**
     * 在指定上级下寻找非财富点位
     * @param int $site_id 站点ID
     * @param int $parent_id 上级ID
     * @param int $max_children 最大子节点数
     * @return array|null 位置信息
     */
    protected function findNonFuPositionUnderParent($site_id, $parent_id, $max_children)
    {
        Log::info('findNonFuPositionUnderParent开始' . 'parent_id:' . $parent_id . 'max_children:' . $max_children);
        $parent = (new LianPubLineModel())
            ->where('site_id', $site_id)
            ->where('member_id', $parent_id)
            ->findOrEmpty();
            
        if ($parent->isEmpty()) {
            return null;
        }
        
        // 获取已经被占用的位置
        $occupied_positions = (new LianPubLineModel())
            ->where('site_id', $site_id)
            ->where('up_pid', $parent_id)
            ->column('position');
        
        // 只寻找普通位置（1到max_children-1），排除财富点位
        for ($i = 1; $i < $max_children; $i++) {
            if (!in_array($i, $occupied_positions)) {
                $new_path = $this->buildPath($parent['path'], $parent_id);
                Log::info('findNonFuPositionUnderParent结束' . 'new_path:' . $new_path);
                return [
                    'up_pid' => $parent_id,
                    'position' => $i,
                    'path' => $new_path,
                    'level' => $parent['level'] + 1,
                    'is_fu' => 0 // 滑落下来的不能是财富点位
                ];
            }
        }
        Log::info('findNonFuPositionUnderParent结束');
        return null;
    }
    
    /**
     * 构建路径字符串
     * @param string $parent_path 上级路径
     * @param int $parent_id 上级ID
     * @return string 新路径
     */
    protected function buildPath($parent_path, $parent_id)
    {
        if (empty($parent_path)) {
            return (string)$parent_id;
        } else {
            return $parent_path . ',' . $parent_id;
        }
    }
    
    /**
     * 在整个网络中查找可用位置（广度优先搜索）
     * @param int $site_id 站点ID
     * @param int $max_children 最大子节点数
     * @return array|null 位置信息
     */
    protected function findAvailablePositionInNetwork($site_id, $max_children)
    {
        Log::info('findAvailablePositionInNetwork开始' . 'max_children:' . $max_children);
        // 按层级和创建时间顺序查找所有非满节点
        $candidates = (new LianPubLineModel())
            ->where('site_id', $site_id)
            ->where('is_full', 0)
            ->order('level ASC, create_time ASC')
            ->select()
            ->toArray();
            
        foreach ($candidates as $node) {
            // 获取已经被占用的位置
            $occupied_positions = (new LianPubLineModel())
                ->where('site_id', $site_id)
                ->where('up_pid', $node['member_id'])
                ->column('position');
            
            // 检查是否有可用的非财富点位
            for ($i = 1; $i < $max_children; $i++) {
                if (!in_array($i, $occupied_positions)) {
                    $new_path = $this->buildPath($node['path'], $node['member_id']);
                    Log::info('findAvailablePositionInNetwork结束' . 'new_path:' . $new_path);
                    return [
                        'up_pid' => $node['member_id'],
                        'position' => $i,
                        'path' => $new_path,
                        'level' => $node['level'] + 1,
                        'is_fu' => 0 // 非财富点位
                    ];
                }
            }
        }
        Log::info('findAvailablePositionInNetwork结束');
        return null;
    }
    
    /**
     * 统计指定节点下非财富点位的可用位置数
     * @param int $site_id 站点ID
     * @param int $member_id 会员ID
     * @param int $max_children 最大子节点数
     * @return int 可用的非财富点位数量
     */
    protected function countNonFuAvailablePositions($site_id, $member_id, $max_children)
    {
        Log::info('111111' . 'site_id:' . $site_id . 'member_id:' . $member_id . 'max_children:' . $max_children);
        // 获取已经被占用的位置
        $occupied_positions = (new LianPubLineModel())
            ->where('site_id', $site_id)
            ->where('up_pid', $member_id)
            ->column('position');
        Log::info('111111' . 'occupied_positions:' . json_encode($occupied_positions));
        
        // 计算可用的非财富点位数量
        $available_count = 0;
        for ($i = 1; $i < $max_children; $i++) { // 不包括财富点位
            if (!in_array($i, $occupied_positions)) {
                $available_count++;
            }
        }
        Log::info('111111' . 'available_count:' . $available_count);
        return $available_count;
    }
    
    /**
     * 更新路径上所有父节点的团队计数
     * @param int $site_id 站点ID
     * @param string $path 路径
     * @return void
     */
    protected function updateParentTeamCounts($site_id, $path)
    {
        if (empty($path)) {
            return; // 如果path为空，说明是根节点，无需更新父节点
        }
        
        $parent_ids = explode(',', $path); // 不需要trim操作，因为path已经没有前后逗号
        if (!empty($parent_ids)) {
            // 过滤掉空值，确保都是有效的ID
            $parent_ids = array_filter($parent_ids, function($id) {
                return !empty($id) && is_numeric($id);
            });
            
            if (!empty($parent_ids)) {
                (new LianPubLineModel())
                    ->where('site_id', $site_id)
                    ->whereIn('member_id', $parent_ids) // 注意这里使用member_id而不是id
                    ->update([
                        'team_count' => ['inc', 1],
                        'update_time' => time()
                    ]);
            }
        }
    }
}